#include "ili9341.h"
#include "cmsis_os.h"
#include <stdlib.h>
//上电后，屏幕是白色，说明没初始化。是灰、暗条纹相间则是初始化好了。
//RES接高，BLK不用接。除此之外，控制屏幕需要CLK、MOSI、DC、CS1，最少需要这4跟线。
//屏幕的spi速率使用25M没问题

SPI_HandleTypeDef *ili9341::spi_ = nullptr;
GPIO_TypeDef *ili9341::dc_GPIOx_ = nullptr, *ili9341::screen_cs_GPIOx_ = nullptr, *ili9341::touch_cs_GPIOx_ = nullptr;
uint16_t ili9341::dc_GPIO_Pin_ = 0, ili9341::screen_cs_GPIO_Pin_ = 0, ili9341::touch_cs_GPIO_Pin_ = 0, ili9341::x = 0, ili9341::y = 0;
void ili9341::init(SPI_HandleTypeDef *spi, GPIO_TypeDef *dc_GPIOx, uint16_t dc_GPIO_Pin, GPIO_TypeDef *screen_cs_GPIOx, uint16_t screen_cs_GPIO_Pin, GPIO_TypeDef *touch_cs_GPIOx, uint16_t touch_cs_GPIO_Pin)
{
    if (!spi || !dc_GPIOx)
        while (1)
            ;

    spi_ = spi;
    dc_GPIOx_ = dc_GPIOx;
    dc_GPIO_Pin_ = dc_GPIO_Pin;
    screen_cs_GPIOx_ = screen_cs_GPIOx;
    screen_cs_GPIO_Pin_ = screen_cs_GPIO_Pin;
    touch_cs_GPIOx_ = touch_cs_GPIOx;
    touch_cs_GPIO_Pin_ = touch_cs_GPIO_Pin;
    screen_init();
    clear();
}

void ili9341::display(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t *data)
{
    if (width == 0 || height == 0)
        width = 1, height = 1;
    set_rect(x, y, width, height);
    send_16way_data_screen(data, height * width);
}

uint8_t ili9341::receiv_8way(void)
{
    uint8_t data;
    HAL_SPI_Receive(spi_, &data, 1, 1000);
    return data;
}

void ili9341::send_8way_data_screen(uint8_t data)
{
    dc1();
    cs1_0();
    send_8way(data);
    cs1_1();
}

void ili9341::send_16way_data_screen(uint16_t *data, uint32_t size) //只有在发送颜色时用
{
    dc1();
    cs1_0();
    while (size--)
    {
        send_8way(*data >> 8);
        send_8way(*data);
        ++data;
    }
    cs1_1();
}

void ili9341::send_comment(uint8_t data)
{
    dc0();
    cs1_0();
    send_8way(data);
    cs1_1();
}

void ili9341::set_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
    //转换为坐标
    width += x;
    width--;
    height += x;
    height--;
    send_comment(0x2a);
    send_16way_data_screen(&x, 1);
    send_16way_data_screen(&width, 1);

    send_comment(0x2b);
    send_16way_data_screen(&y, 1);
    send_16way_data_screen(&height, 1);

    send_comment(0x2C);
}

void ili9341::screen_init(void)
{
    osDelay(200);

    send_comment(0xCF);
    send_8way_data_screen(0x00);
    send_8way_data_screen(0xD9);
    send_8way_data_screen(0X30);

    send_comment(0xED);
    send_8way_data_screen(0x64);
    send_8way_data_screen(0x03);
    send_8way_data_screen(0X12);
    send_8way_data_screen(0X81);

    send_comment(0xE8);
    send_8way_data_screen(0x85);
    send_8way_data_screen(0x10);
    send_8way_data_screen(0x78);

    send_comment(0xCB);
    send_8way_data_screen(0x39);
    send_8way_data_screen(0x2C);
    send_8way_data_screen(0x00);
    send_8way_data_screen(0x34);
    send_8way_data_screen(0x02);

    send_comment(0xF7);
    send_8way_data_screen(0x20);

    send_comment(0xEA);
    send_8way_data_screen(0x00);
    send_8way_data_screen(0x00);

    send_comment(0xC0);          //Power control
    send_8way_data_screen(0x21); //VRH[5:0]

    send_comment(0xC1);          //Power control
    send_8way_data_screen(0x12); //SAP[2:0];BT[3:0]

    send_comment(0xC5); //VCM control
    send_8way_data_screen(0x32);
    send_8way_data_screen(0x3C);

    send_comment(0xC7); //VCM control2
    send_8way_data_screen(0XC1);

    send_comment(0x36); // Memory Access Control
    send_8way_data_screen(0x08);

    send_comment(0x3A);
    send_8way_data_screen(0x55);

    send_comment(0xB1);
    send_8way_data_screen(0x00);
    send_8way_data_screen(0x18);

    send_comment(0xB6); // Display Function Control
    send_8way_data_screen(0x0A);
    send_8way_data_screen(0xA2);

    send_comment(0xF2); // 3Gamma Function Disable
    send_8way_data_screen(0x00);

    send_comment(0x26); //Gamma curve selected
    send_8way_data_screen(0x01);

    send_comment(0xE0); //Set Gamma
    send_8way_data_screen(0x0F);
    send_8way_data_screen(0x20);
    send_8way_data_screen(0x1E);
    send_8way_data_screen(0x09);
    send_8way_data_screen(0x12);
    send_8way_data_screen(0x0B);
    send_8way_data_screen(0x50);
    send_8way_data_screen(0XBA);
    send_8way_data_screen(0x44);
    send_8way_data_screen(0x09);
    send_8way_data_screen(0x14);
    send_8way_data_screen(0x05);
    send_8way_data_screen(0x23);
    send_8way_data_screen(0x21);
    send_8way_data_screen(0x00);

    send_comment(0XE1); //Set Gamma
    send_8way_data_screen(0x00);
    send_8way_data_screen(0x19);
    send_8way_data_screen(0x19);
    send_8way_data_screen(0x00);
    send_8way_data_screen(0x12);
    send_8way_data_screen(0x07);
    send_8way_data_screen(0x2D);
    send_8way_data_screen(0x28);
    send_8way_data_screen(0x3F);
    send_8way_data_screen(0x02);
    send_8way_data_screen(0x0A);
    send_8way_data_screen(0x08);
    send_8way_data_screen(0x25);
    send_8way_data_screen(0x2D);
    send_8way_data_screen(0x0F);

    send_comment(0x11); //Exit Sleep
    osDelay(200);
    send_comment(0x29); //Display on
}

void ili9341::clear()
{
    uint16_t color = 0;
    set_rect(0, 0, screen_width_, screen_height_);
    for (uint32_t i = 0; i < screen_width_ * screen_height_; ++i)
        send_16way_data_screen(&color, 1);
}

int cmp(const void *a, const void *b)
{
    return *(uint16_t *)a - *(uint16_t *)b; //需要与被测类型一致
}

//测出来的x，y：max:3855,3855 min:2184, 2184
static const float fx = (3855 - 2184) / 240.0;
static const float fy = (3855 - 2184) / 320.0;
static const uint8_t count = 9;
uint16_t x_data[count], y_data[count];
void ili9341::touch(void)
{
    if (!touch_cs_GPIOx_)
        while (1)
            ;
    //速率不要高于5MHz //xpt2046
    cs2_0();
    for (uint8_t i = 0; i < count; i++)
    {
        send_8way(0xd0);
        x = receiv_8way();
        x <<= 8;
        x |= receiv_8way();
        x >>= 4;
        x_data[i] = x;

        send_8way(0x90);
        y = receiv_8way();
        y <<= 8;
        y |= receiv_8way();
        y >>= 4;
        y_data[i] = y;
    }
    qsort(x_data, count, sizeof(x_data[0]), cmp);
    qsort(y_data, count, sizeof(y_data[0]), cmp);
    x = (x_data[count >> 1] - 2184) / fx;
    y = (y_data[count >> 1] - 2184) / fy;
    cs2_1();
}